#include "Sphere.h"

/// <Summary> The collision type of this object </Summary>
const HashString Sphere::COLLISIONTYPE("COLLISION_SPHERE");

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Builds the bounding volume from a set of points </Summary>
///
/// <Param name="verts">   	The verts </Param>
/// <Param name="numVerts">	Number of verts </Param>
////////////////////////////////////////////////////////////////////////////////////////////////////
void Sphere::Build(const Vector3* verts, unsigned int numVerts)
{
	Vector3 minPoint( FLT_MAX, FLT_MAX, FLT_MAX );
	Vector3 maxPoint( -FLT_MAX, -FLT_MAX, -FLT_MAX );

	for( unsigned int i = 0; i < numVerts; ++i )
	{
		for(unsigned int j = 0; j < 3; ++j )
		{
			minPoint.arr[j] = min( minPoint.arr[j], verts[i].arr[j] );
			maxPoint.arr[j] = max( maxPoint.arr[j], verts[i].arr[j] );
		}
	}

	center = (maxPoint + minPoint) * 0.5f;
	radius = 0.0f;

	for( unsigned int i = 0; i < numVerts; ++i )
	{
		radius = max( radius,
			(verts[i].x - center.x) * (verts[i].x - center.x) + 
			(verts[i].y - center.y) * (verts[i].y - center.y) + 
			(verts[i].z - center.z) * (verts[i].z - center.z) );
	}

	radius = sqrt( radius );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	
/// 	Builds the bound volume from two other bounding volumes of the same type 
/// </Summary>
///
/// <Param name="bounds1">	The first bounds </Param>
/// <Param name="bounds2">	The second bounds </Param>
////////////////////////////////////////////////////////////////////////////////////////////////////
void Sphere::Build(const IBoundingCollideAble* bounds1, const IBoundingCollideAble* bounds2)
{
	if( bounds1->GetCollisionType() != Sphere::COLLISIONTYPE || bounds2->GetCollisionType() != Sphere::COLLISIONTYPE )
		return;

	Sphere* sphere1 = (Sphere*)bounds1;
	Sphere* sphere2 = (Sphere*)bounds2;

	Vector3 distance = sphere2->center - sphere1->center;

	float dotresult = DotProduct( distance, distance );

	if( (sphere2->radius - sphere1->radius)*(sphere2->radius - sphere1->radius) >= dotresult )
	{
		if( sphere2->radius >= sphere1->radius )
		{
			this->center = sphere2->center;
			this->radius = sphere2->radius;
		}
		else
		{
			this->center = sphere1->center;
			this->radius = sphere1->radius;
		}
	}
	else
	{
		float dist = sqrt(dotresult);
		this->radius = (dist + sphere1->radius + sphere2->radius) * 0.5f;
		this->center = sphere1->center;

		if( dist > FLT_EPSILON )
			this->center += distance * ((radius - sphere1->radius) / dist);
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Transforms this object by a matrix </Summary>
///
/// <Param name="transform">	The transform matrix	</Param>
////////////////////////////////////////////////////////////////////////////////////////////////////
void Sphere::Transform(const Matrix4x4& transform)
{
	Vector3 point;
	TranslateVector( point, center, transform ); 
	center = point;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Translates this object </Summary>
///
/// <Param name="translation">	The translation vector	</Param>
////////////////////////////////////////////////////////////////////////////////////////////////////
void Sphere::Translate(const Vector3& translation)
{
	center += translation;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
/// <Summary>	Prints this object to the console </Summary>
///
/// <Param name="out">	The console window </Param>
///
/// <Return>	The console window </Return>
////////////////////////////////////////////////////////////////////////////////////////////////////
ConsoleWindow& Sphere::Print(ConsoleWindow& out) const
{
	return out << "\nSPHERE:\n" << "Center:  " << center << "\nRadius:  " << radius << "\n";
}